Skip to main content

ECB CBC WTF

Here you can encrypt in CBC but only decrypt in ECB. That shouldn't be a weakness because they're different modes... right?

source.py
from Crypto.Cipher import AES

KEY = ?
FLAG = ?

@chal.route('/ecbcbcwtf/decrypt/<ciphertext>/')
def decrypt(ciphertext):
ciphertext = bytes.fromhex(ciphertext)

cipher = AES.new(KEY, AES.MODE_ECB)
try:
decrypted = cipher.decrypt(ciphertext)
except ValueError as e:
return {"error": str(e)}

return {"plaintext": decrypted.hex()}


@chal.route('/ecbcbcwtf/encrypt_flag/')
def encrypt_flag():
iv = os.urandom(16)

cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(FLAG.encode())
ciphertext = iv.hex() + encrypted.hex()

return {"ciphertext": ciphertext}

Solution:

This WriteUp Solution is password protected by the flag of the challenge.

The problem here is that the decrypt function is using ECB mode, but the encrypt_flag function is using CBC mode. This means that the first block of the ciphertext is the IV, and the rest of the ciphertext is the encrypted flag. The IV is random, so we can't just guess it. However, we can use the fact that ECB mode is deterministic to our advantage.

we know iviv and m=Enck(miv)m'=Enc_k(m \oplus iv) and after decryption with M=Deck(m)M=Dec_k(m') so will get m=Mivm=M \oplus iv and for new block iv=miv=m' and repeat the process for each block of ciphertext and get the flag. Code for the the same is

solve.py
import requests
# for decryption
url_dc = "https://aes.cryptohack.org/ecbcbcwtf/decrypt/"
url_en = "https://aes.cryptohack.org/ecbcbcwtf/encrypt_flag/"

from Crypto.Util.number import long_to_bytes

def decrypt(ciphertext):
r=requests.get(url_dc+ciphertext)
return r.json()['plaintext']

def main():
# get ciphertext
r = requests.get(url_en)
c = r.json()['ciphertext']
iv=int(c[:32],16)
flag=b""
c=c[32:] #remove iv

for i in range(0,len(c),32):
dec=decrypt(c[i:i+32])
block = int(dec,16)
flag+=long_to_bytes(iv^block)
iv=int(c[i:i+32],16)
print(flag)

main()

After running the code we get the flag crypto{3cb_5uck5_4v01d_17_!!!!!}